
import * as cc from "cc";
import { Loger } from "../loger/Loger";
import { C } from "./ClickableMgr";

export default class NodeUtils {

    /**
     * 根据数据和预制体批量创建node节点
     * @param arrData 数组类型数据
     * @param prefab 预制体
     * @param interval 生成间隔(秒)
     * @param setItemFunc 生成一个时的回调
     * @param target 回调方法bind目标
     * @returns 
     */
    static genNodeWithPrefabAndData(arrData: any[], prefab: cc.Prefab | cc.Node, interval: number, setItemFunc: (node: cc.Node, data: any, idx: number) => void, target: any): Promise<void> {
        target = target ? target : this;
        cc.Tween.stopAllByTarget(target);
        if (!arrData || arrData.length === 0) {
            return Promise.resolve();
        }
        return new Promise<void>((resolve, reject) => {
            let from = 0;
            let to = arrData.length;
            let tweenObj = cc.tween(target).call(() => {
                let subItem = cc.instantiate(prefab);
                setItemFunc.bind(target)(subItem, arrData[from], from);
                from++;
            }).delay(interval)
            cc.tween(target).repeat(to - from, tweenObj)
                .call(() => {
                    resolve();
                })
                .start();

        })
    }

    static getWorldRect(node: cc.Node): cc.Rect {
        let uiTrans = node.getComponent(cc.UITransform);
        let wordPos = uiTrans.convertToWorldSpaceAR(cc.Vec3.ZERO)
        let x = wordPos.x - uiTrans.width * uiTrans.anchorX;
        let y = wordPos.y - uiTrans.height * uiTrans.anchorY;
        let width = uiTrans.width;
        let height = uiTrans.height;
        let rect = new cc.Rect(x, y, width, height);
        return rect
    }

    /**获取组件 如果不存在 则添加 */
    static getOrAddComponent<T extends cc.Component>(node: cc.Node, type: any): T {
        return node.getComponent<T>(type) || node.addComponent<T>(type)
    }

    static getOrAddComponentByName(node: cc.Node, className: string): any {
        return node.getComponent(className) || node.addComponent(className);
    }

    /**获取子节点,不存在 则添加 */
    static getOrAddChildNode(parent: cc.Node, childName: string): cc.Node {
        let child = parent.getChildByName(childName)
        if (child == null) {
            child = new cc.Node(childName)
            child.setParent(parent);
        }
        return child
    }


    /**计算两个node之间距离 */
    static getNodeDis(node1: cc.Node, node2: cc.Node): number {
        let trans1 = node1.getComponent(cc.UITransform);
        let trans2 = node2.getComponent(cc.UITransform);
        let pos1 = trans1.convertToWorldSpaceAR(cc.Vec3.ZERO)
        let pos2 = trans2.convertToWorldSpaceAR(cc.Vec3.ZERO)
        return pos1.subtract(pos2).length();
    }

    /**计算两个node之间距离平方,用于比较大小 */
    static getNodeDisSqr(node1: cc.Node, node2: cc.Node): number {
        let trans1 = node1.getComponent(cc.UITransform);
        let trans2 = node2.getComponent(cc.UITransform);
        let pos1 = trans1.convertToWorldSpaceAR(cc.Vec3.ZERO)
        let pos2 = trans2.convertToWorldSpaceAR(cc.Vec3.ZERO)
        return pos1.subtract(pos2).lengthSqr();
    }

    /**设置适配,相对于父节点铺满 */
    static resetWidgitFullScreen(widgit: cc.Widget) {
        widgit.isAlignLeft = true
        widgit.isAlignRight = true
        widgit.isAlignBottom = true
        widgit.isAlignTop = true
        widgit.left = 0
        widgit.right = 0
        widgit.top = 0
        widgit.bottom = 0
    }

    /**
     * 给一个控件绑定点击事件
     */
    static setClickListenerAnim(node: cc.Node | cc.Component, anim: boolean, clickListener: (ev: cc.EventTouch) => void, target?: any, checkClickAble: boolean = false) {
        let nd = (node instanceof cc.Component) ? node.node : node
        let trans = nd.getComponent(cc.UITransform);
        if (!(nd instanceof cc.Node)) {
            Loger.logView("setClickListener node param incorrect!", node)
            return;
        }
        let isMove = false;
        let pos = null;
        let startPos = null;
        const nodeScaleX = nd.scale.x;
        const nodeScaleY = nd.scale.y;
        nd.targetOff(target ? target : this);

        nd.on(cc.Node.EventType.TOUCH_START, function (ev: cc.EventTouch) {
            isMove = false;
            pos = ev.getLocation();
            startPos = pos;
            ev.propagationStopped = true;
            if (anim && ev.target instanceof cc.Node) {
                ev.target.setScale(0.95 * nodeScaleX, 0.95 * nodeScaleY);
            }

        }.bind(target ? target : this), target ? target : this)
        nd.on(cc.Node.EventType.TOUCH_MOVE, function (ev: cc.EventTouch) {
            pos = ev.getLocation()
            startPos = ev.getStartLocation()
            const sub = pos.subtract(startPos).length();
            if (sub > 20) {
                isMove = true
            }

        }.bind(target ? target : this), target ? target : this)
        nd.on(cc.Node.EventType.TOUCH_CANCEL, function (ev: cc.EventTouch) {
            if (anim && ev.target instanceof cc.Node) {
                ev.target.setScale(nodeScaleX, nodeScaleY);
            }

        }.bind(target ? target : this), target ? target : this)
        nd.on(cc.Node.EventType.TOUCH_END, function (ev: cc.EventTouch) {
            ev.getLocation()
            ev.propagationStopped = true;
            if (anim && ev.target instanceof cc.Node) {
                ev.target.setScale(nodeScaleX, nodeScaleY);
            }
            if (!isMove) {
                if (checkClickAble && !C.getT(ev).isOk) {
                    //按钮点击过快
                    return;
                }
                clickListener.bind(target ? target : this)(ev)
            }
        }.bind(target ? target : this), target ? target : this)
    }

    /**
     * @desc node置灰
     * @param target 
     * @param gary 是否置灰 
     */
    public static setNodeGray(target: cc.Node | cc.Sprite | cc.Label | cc.sp.Skeleton, gary: boolean = true) {
        if (!target) {
            return
        }
        if (target instanceof cc.Node) {
            let component = target.getComponent(cc.Sprite) || target.getComponent(cc.Label)
            this.setNodeGray(component, gary)

            let children = target.children
            for (let index = 0; index < children.length; index++) {
                const child = children[index];
                this.setNodeGray(child, gary)
            }
        } else {
            // 使用内置基于物理的光照着色器（PBR）‘builtin-standard.effect’ 初始化材质            
            const mat = new cc.Material();
            let materialName = gary ? "ui-sprite-gray-material" : "ui-sprite-material"            
            mat.initialize({ effectName: materialName });
            //TODO 获取内置材质取不到，可能方法不对，后面有时间处理

            target.setSharedMaterial(mat,0)
        }
    }
}